package com.cskaoyan.javase.oop2._1extends._8hidden;

/**
 * 属性的隐藏
 * 思考: 父子类中能不能出现同名成员变量? 允许
 * 父子类的成员是允许同名的。那么如果父子类属性同名了，那么不使用super区分，创建子类对象,直接访问的效果是什么样的呢？
 *
 * 现在我们直接创建子类对象，使用子类引用接收。会发现访问的结果是子类中属性的取值，那么父类中的那个成员变量去哪了呢？首先它肯定是存在的，这一点随便写一个父类成员变量的Getter方法就可以验证了。这说明使用 "对象名点"访问成员变量 这个语法，可能存在一些特殊的机制，接下来我们就来探讨这种机制。
 *
 * 探究对象名点访问成员变量的访问机制,主要从以下两个角度:
 *      1.访问范围,能够访问到哪些成员变量
 *      2.访问的结果.
 *
 * 当然既然是对象名点访问成员变量,那么创建对象,目前有三种形式:
 *      1.创建子类对象,用子类引用接收
 *      2.创建父类对象,用父类引用接收
 *      3.创建子类对象,但是用父类引用接收
 *
 * 首先研究访问范围,访问范围是一个编译上的概念,能访问到不会编译报错,反之会编译报错.和程序运行是无关的
 *      探究三种创建对象的方式,它们的访问范围:
 *          1.创建子类对象,用子类引用接收
 *              访问范围是: 父类 + 子类
 *
 *          2.创建父类对象,用父类引用接收
 *              访问范围是: 父类
 *
 *          3.创建子类对象,但是用父类引用接收
 *              访问范围是: 父类
 *
 *     综上,对象名点成员变量,它的访问范围是根据引用的数据类型来决定的,和对象的具体类型无关.
 *     具体来说,决定访问范围时,如果这个引用是一个子类,那么访问范围是"父+子"
 *     如果引用是一个父类,那么访问范围是"父"
 *     这说明编译器在查找能否访问成员变量时,可以向上查引用的数据类型的父类,但是不能查它的子类
 *     通俗点来说,Java中,一个子类是知道自己有爸爸
 *     一个爸爸不知道它有儿子.
 *
 *
 * 接下来研究一下访问结果:
 *      1.创建子类对象,用子类引用接收
 *          子类中的结果
 *      2.创建父类对象,用父类引用接收
 *          父类中的结果
 *      3.创建子类对象,但是用父类引用接收
 *          父类中的结果
 *
 *  综上,对象名点成员变量,它的访问结果也是根据引用数据类型来决定,会体现出引用数据类型中的结果
 *
 *  以上总结:
 *      用对象名点访问成员变量,无论是访问范围,还是访问结果,都只需要看引用的类型即可.对象是什么都无所谓.
 *
 *
 * 注意事项：
 * 父子类中的同名成员变量它们各自有存储的区域，父类的同名成员变量被子类同名成员变量隐藏了，称之为"属性的隐藏"。
 * 但我们仍然可以通过父类中的Getter方法，或者通过super去访问到父类中同名成员变量，当然它们都受访问权限限制。
 * 静态成员变量在父子类中也存在同名的情况，但是它们不是覆盖也不是隐藏，而是互相独立的两个静态成员变量
 *
 * @since 16:14
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*
        // 研究访问范围
        Son s = new Son();
        System.out.println(s.fatherNum);
        System.out.println(s.sonNum);
        System.out.println(s.num);

        Father f = new Father();
        // f.sonNum;

        Father fs = new Son();
        // fs.sonNum*/

        // 研究访问结果
        /*Son s = new Son();
        System.out.println(s.num);
        Father f = new Father();
        System.out.println(f.num);
        Father fs = new Son();
        System.out.println(fs.num);*/

        Father fs = new Son(666, 777);
        System.out.println((fs).num);
    }
}

class Father {
    int num = 10;
    // 父类独有成员变量
    int fatherNum = 20;

    public int getNum() {
        return num;
    }

    public Father() {
    }

    public Father(int num) {
        this.num = num;
    }
}

class Son extends Father {
    int num = 100;
    // 子类独有成员变量
    int sonNum = 200;

    public Son() {
    }

    public Son(int num, int num1) {
        super(num);
        this.num = num1;
    }
}